package com.hutra.bitmap {
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.TimerEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import com.hutra.bitmap.*;
	/**
	 * An MovieMix is a bitmap object that uses a sequence of images
	 * from a provided bitmap to play an animation.
	 * @example http://blog.hutrasoft.com/2011/12/movieclip-to-animated-bitmap.html
	 * @see		http://code.google.com/p/hutra/
	 * @see     svn http://code.google.com/p/hutra/
	 * @author hungconcon
	 * @version 1.0.0.1
	 */
	public class MovieMix extends Bitmap{
		/**
		 * The buffer to store the whole bitmap.
		 * @private
		 */
		private var thisbuffer:BitmapData;
		/**
		 * Timer used for frame animation.
		 * @private
		 */
		private var thistime:EnterFrame;
		
		/**
		 * The number of frames that the animated bitmap has.
		 * @private
		 */
		private var frameamount:int;
		
		/**
		 * Used for the onTimer function to count loops.
		 * @private
		 */
		private var framenr:int;
		
		/**
		 * Determines if the animTile is already playing or not.
		 * @private
		 */
		private var isplay:Boolean;
		
		/**
		 * Rectangle object used for copyPixels operation.
		 * @private
		 */
		private var thisrect:Rectangle;
		
		private var onwidth:Number;
		private var onheight:Number;
		/**
		 * 
		 */
		private var listbitmap:Array;
		
		
		// Constructor ////////////////////////////////////////////////////////////////
		
		/**
		 * Creates a new MoviePix instance.
		 * 
		 * @param bitmap The bitmapData object that contains the image sequence
		 *         for the animated bitmap.
		 * @param inwidth The width of the animated bitmap.
		 * @param inheight The height of the animated bitmap.
		 * @param timer The frame rate timer used for the animated bitmap.
		 */
		public function MovieMix(listdata:Array,inwidth:Number,inheight:Number,fpt:Number,transparent:Boolean = true,pixelSnapping:String = "auto",smoothing:Boolean = false){
			
			super(new BitmapData(inwidth, inheight, transparent, 0x00000000), pixelSnapping, smoothing);
			
			onwidth = inwidth;
			onheight = inheight;
			
			listbitmap = listdata;
			
			thisbuffer = listdata[0].clone();
			frameamount = listdata.length;
			
			framenr = 1;
			isplay = false;
			thistime = new EnterFrame(fpt);
			
			thisrect = new Rectangle(0, 0, inwidth, inheight);
			bitmapData.copyPixels(thisbuffer, thisrect, new Point(0, 0));
		}
		/**
		 * Use in case you do not want to initialize the class
		 * Allows flexible switch its middle the other clip
		 * @param	listdata
		 * @param	inwidth
		 * @param	inheight
		 * @param	fpt
		 * @param	transparent
		 */
		public function setMix(listdata:Array, inwidth:Number, inheight:Number, transparent:Boolean = true):void {
			
			bitmapData.dispose();
			bitmapData = new BitmapData(inwidth, inheight, transparent, 0x00000000);
			
			//clearListBase(listbitmap);
			
			onwidth = inwidth;
			onheight = inheight;
			
			listbitmap = listdata;
			
			thisbuffer = listdata[0].clone();
			frameamount = listdata.length;
			framenr = 1;
		}
		/**
		 * Frees memory!
		 * @param	the arraylist
		 */
		private function clearListBase(a:Array):void {
			if (a == null) return;
			for (var i:int = 0; i < a.length; i++) delete a.splice(i, 1);
			if(a!=null) if (a.length > 0) clearListBase(a);
			a = null;
		}
		// Public Methods /////////////////////////////////////////////////////////////
		
		/**
		 * Sets the frame rate timer object used for the animated
		 * bitmap. This method is useful when it is desired to change
		 * the framerate at a later timer.
		 * 
		 * @param timer The frame rate timer used for the animated bitmap.
		 */
		public function setFrameRateTimer(fpt:int):void {
			var timer:EnterFrame = new EnterFrame(fpt);
			if (isplay){
				stop();
				thistime = timer;
				play();
			}
			else
			{
				thistime = timer;
			}
		}
		
		/**
		 * Returns the frame rate with that the animated bitmap is playing.
		 * 
		 * @return The fps value of the animated bitmap.
		 */
		public function getFrameRate():int
		{
			return thistime.getFrameRate();
		}
		
		/**
		 * Returns the current frame position of the animated bitmap.
		 * 
		 * @return The current frame position.
		 */
		public function getCurrentFrame():int
		{
			return framenr;
		}
		
		/**
		 * Returns the total amount of frames that the animated bitmap has.
		 * 
		 * @return The total frame amount.
		 */
		public function getTotalFrames():int
		{
			return frameamount;
		}
		
		/**
		 * Returns whether the animated bitmap is playing or not.
		 * 
		 * @return true if the animated bitmap is playing, else false.
		 */
		public function isPlaying():Boolean
		{
			return isplay;
		}
		
		/**
		 * Starts the playback of the animated bitmap. If the animated
		 * bitmap is already playing while calling this method, it calls
		 * stop() and then play again instantly to allow for framerate
		 * changes during playback.
		 */
		public function play():void
		{
			if (!isplay)
			{
				isplay = true;
				thistime.addEventListener(TimerEvent.TIMER, playForward);
				thistime.start();
			}
			else
			{
				stop();
				play();
			}
		}
		
		/**
		 * Stops the playback of the animated bitmap.
		 */
		public function stop():void
		{
			if (isplay)
			{
				thistime.stop();
				thistime.removeEventListener(TimerEvent.TIMER, playForward);
				isplay = false;
			}
		}
		
		/**
		 * Jumps to the specified value and plays the animated
		 * bitmap from that position. Note that the frames of an
		 * animated bitmap start at 1.
		 * 
		 * @param value The frame number to which to jump.
		 */
		public function gotoAndPlay(value:int):void
		{
			framenr = value;// - 1;
			//if (framenr == 0) { framenr = 1; }
			if (value > frameamount) {
				framenr = frameamount;
			}
			play();
		}
		
		/**
		 * Jumps to the specified value and stops the animated
		 * bitmap at that position. Note that the frames of an
		 * animated bitmap start at 1.
		 * 
		 * @param value The frame number to which to jump.
		 */
		public function gotoAndStop(value:int):void{
			if (value >= framenr){
				framenr = value - 1;
				nextFrame();
			}else{
				framenr = value + 1;
				prevFrame();
			}
		}
		
		/**
		 * Moves the animation to the next of the current frame.
		 * If the animated bitmap is playing, the playback is
		 * stopped by this operation.
		 */
		public function nextFrame():void{
			if (isplay) stop();
			framenr++;
			if (framenr > frameamount) framenr = frameamount;
			draw();
		}
		
		/**
		 * Moves the animation to the previous of the current frame.
		 * If the animated bitmap is playing, the playback is
		 * stopped by this operation.
		 */
		public function prevFrame():void
		{
			if (isplay) stop();
			framenr--;
			if (framenr < 1) framenr = 1;
			draw();
		}
		
		/**
		 * Plays the animation forward by one frame.
		 * @private
		 */
		private function playForward(event:TimerEvent = null):void
		{
			framenr++;
			if (framenr > frameamount) framenr = 1;
			else if (framenr < 1) framenr = frameamount;
			draw();
		}
		/**
		 * Draws the next bitmap frame from the buffer to the animated bitmap.
		 * Noted, it logig with onwidth and on onheight
		 * @private
		 */
		private function draw():void{
			dispatchEvent(new EnterEvent(EnterEvent.ENTER));
			var db:BitmapData = listbitmap[framenr - 1];
			bitmapData.copyPixels(db,db.rect,new Point(0,0));
		}
	}
}
